//
// Created by Vincent_Vic on 2020/4/23.
//

#ifndef DATAORGANIZATION_UNIONFIND_H
#define DATAORGANIZATION_UNIONFIND_H


#include <cassert>

namespace UF1 {
    class UnionFind {
    private:
        int* id;
        int count;
    public:

        explicit UnionFind(int count) : count(count) {
            id = new int [count];
            for (int i = 0; i < count; ++i) {
                id[i] = i;
            }
        }

        virtual ~UnionFind(){
            delete [] id;
            id = nullptr;
        }

        int find(int position){
            assert(position >= 0 && position < count);
            return id[position];
        }

        bool isConnected(int p,int q ){
            return find(p) == find(q);
        }

        void unionElements(int p,int q){
            int pID = find(p);
            int qID = find(q);
            if (pID == qID)
                return;
            for (int i=0;i<count;i++){
                if (id[i] == pID)
                    id[i] = qID;
            }

        }
    };
}

namespace UF2 {
    class UnionFind {
    private:
        int* parent;
        int count;
    public:

        explicit UnionFind(int count) : count(count) {
            parent = new int [count];
            for (int i = 0; i < count; ++i) {
                parent[i] = i;
            }
        }

        virtual ~UnionFind(){
            delete [] parent;
            parent = nullptr;
        }

        int find(int position){
            assert(position >= 0 && position < count);
            //找父节点
            while (position != parent[position]){
                position = parent[position];
            }
            return position;
        }

        //判断是否同样的根
        bool isConnected(int p,int q ){
            return find(p) == find(q);
        }


        void unionElements(int p,int q){

            //找到两数的根
            int pRoot = find(p);
            int qRoot = find(q);
            //如果已经存在了
            if (pRoot == qRoot)
                return;
            //p的根指向q的根
            parent[pRoot] = qRoot;

        }
    };


}

namespace UF3 {
    class UnionFind {
    private:
        int* parent;
        int* sz; //以i为根的个数
        int count;
    public:

        explicit UnionFind(int count) : count(count) {
            parent = new int [count];
            sz = new int[count];
            for (int i = 0; i < count; ++i) {
                parent[i] = i;
                sz[i]=1;
            }
        }

        virtual ~UnionFind(){
            delete [] parent;
            parent = nullptr;
            delete [] sz;
            sz = nullptr;
        }

        int find(int position){
            assert(position >= 0 && position < count);
            //找父节点
            while (position != parent[position]){
                position = parent[position];
            }
            return position;
        }

        //判断是否同样的根
        bool isConnected(int p,int q ){
            return find(p) == find(q);
        }


        void unionElements(int p,int q){

            //找到两数的根
            int pRoot = find(p);
            int qRoot = find(q);
            //如果已经存在了
            if (pRoot == qRoot)
                return;
            //p的根下的少，指向q的根
            if (sz[pRoot] <= sz[qRoot]) {
                //p的根指向q的根
                parent[pRoot] = qRoot;
                //q的根增加
                sz[qRoot] += sz[pRoot];
            } else{ //相反
                parent[qRoot] = pRoot;
                //p的根增加
                sz[pRoot]+= sz[qRoot];
            }

        }
    };


}

namespace UF4 {
    class UnionFind {
    private:
        int* parent;
        int* rank; //以i为根的层数
        int count;
    public:

        explicit UnionFind(int count) : count(count) {
            parent = new int [count];
            rank = new int[count];
            for (int i = 0; i < count; ++i) {
                parent[i] = i;
                rank[i]=1;
            }
        }

        virtual ~UnionFind(){
            delete [] parent;
            parent = nullptr;
            delete [] rank;
            rank = nullptr;
        }

        int find(int position){
            assert(position >= 0 && position < count);
            //找父节点
            while (position != parent[position]){
                position = parent[position];
            }
            return position;
        }

        //判断是否同样的根
        bool isConnected(int p,int q ){
            return find(p) == find(q);
        }


        void unionElements(int p,int q){

            //找到两数的根
            int pRoot = find(p);
            int qRoot = find(q);
            //如果已经存在了
            if (pRoot == qRoot)
                return;
            //p的根下的层数少，指向q的根
            if (rank[pRoot] < rank[qRoot]) {
                //p的根指向q的根
                parent[pRoot] = qRoot;
            } else if (rank[pRoot] > rank[qRoot]){ //相反
                parent[qRoot] = pRoot;
            } else{ // 层数相同的情况下
                parent[pRoot] = qRoot;
                rank[qRoot] ++;
            }



        }
    };


}

//路径压缩
namespace UF5 {
    class UnionFind {
    private:
        int* parent;
        int* rank; //以i为根的层数
        int count;
    public:

        explicit UnionFind(int count) : count(count) {
            parent = new int [count];
            rank = new int[count];
            for (int i = 0; i < count; ++i) {
                parent[i] = i;
                rank[i]=1;
            }
        }

        virtual ~UnionFind(){
            delete [] parent;
            parent = nullptr;
            delete [] rank;
            rank = nullptr;
        }

        int find(int position){
            assert(position >= 0 && position < count);
            //找父节点
            while (position != parent[position]){
                //路径压缩算法
                //父节节点等于下一个父亲节点
                parent[position] = parent[parent[position]];
                position = parent[position];
            }
            return position;
        }

        //判断是否同样的根
        bool isConnected(int p,int q ){
            return find(p) == find(q);
        }


        void unionElements(int p,int q){

            //找到两数的根
            int pRoot = find(p);
            int qRoot = find(q);
            //如果已经存在了
            if (pRoot == qRoot)
                return;
            //p的根下的层数少，指向q的根
            if (rank[pRoot] < rank[qRoot]) {
                //p的根指向q的根
                parent[pRoot] = qRoot;
            } else if (rank[pRoot] > rank[qRoot]){ //相反
                parent[qRoot] = pRoot;
            } else{ // 层数相同的情况下
                parent[pRoot] = qRoot;
                rank[qRoot] ++;
            }



        }
    };


}

//路径压缩 优化2
namespace UF6 {
    class UnionFind {
    private:
        int* parent;
        int* rank; //以i为根的层数
        int count;
    public:

        explicit UnionFind(int count) : count(count) {
            parent = new int [count];
            rank = new int[count];
            for (int i = 0; i < count; ++i) {
                parent[i] = i;
                rank[i]=1;
            }
        }

        virtual ~UnionFind(){
            delete [] parent;
            parent = nullptr;
            delete [] rank;
            rank = nullptr;
        }

        int find(int position){
            assert(position >= 0 && position < count);
            //找父节点  递归查找，直接让父节点指向根节点，减少层数
            if (position != parent[position])
                parent[position] = find(parent[position]);
            return parent[position];
        }

        //判断是否同样的根
        bool isConnected(int p,int q ){
            return find(p) == find(q);
        }


        void unionElements(int p,int q){

            //找到两数的根
            int pRoot = find(p);
            int qRoot = find(q);
            //如果已经存在了
            if (pRoot == qRoot)
                return;
            //p的根下的层数少，指向q的根
            if (rank[pRoot] < rank[qRoot]) {
                //p的根指向q的根
                parent[pRoot] = qRoot;
            } else if (rank[pRoot] > rank[qRoot]){ //相反
                parent[qRoot] = pRoot;
            } else{ // 层数相同的情况下
                parent[pRoot] = qRoot;
                rank[qRoot] ++;
            }



        }
    };


}
#endif //DATAORGANIZATION_UNIONFIND_H
